# LeetCode 279、完全平方数

# 一、题目描述

给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, …)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。

给你一个整数 n ,返回和为 n 的完全平方数的 最少数量

# 二、题目解析

# 三、参考代码

# 1、Java 代码

class Solution {
    public int numSquares(int n) {


        // 设置一个数组,用来存储小于 n 的那些完全平方数
        List<Integer> square = new ArrayList<>();

        // 通过一个下标来计算
        int idx = 1;

        // 直到 idx * idx 超过了 n 为止
        while (idx * idx <= n) {
            // square 存储小于 n 的那些完全平方数
            square.add(idx * idx);

            // idx 累加
            idx++;
        }

        // dp[0] 表示数字 0  需要完全平方数的最少数量
        // dp[1] 表示数字 0  需要完全平方数的最少数量
        // dp[i] 表示数字 i  需要完全平方数的最少数量
        int[] dp = new int[ n + 1 ];

        // 先让 dp 初始化为 -1,代表 dp[i] 还没有计算
        Arrays.fill(dp,-1);

        // dp[0] 表示数字 0  需要完全平方数的最少数量
        dp[0] = 0;
        
        // 开始填充 dp[]
        for(int i = 1 ; i <= n ;i++){
            
            // 在每次填充的过程中,都去遍历 square 数组
            for(int j = 0 ;j < square.size();j++){
                // 如果发现此时 square 的元素值大于了 i
                // 那么 square 后面的那些元素没有必要参与进来计算 i 了
                // 直接退出当前的 j 的循环判断,让 i++
                if(square.get(j) > i){
                    break;
                }

                // 否则,如果 dp[i] 还没有找到数字 i 需要完全平方数的最少数量
                // 或者此时计算的新值更小,那么更新 dp[i]
                if(dp[i] == -1 || dp[i] > dp[i-square.get(j)] + 1){

                    // 更新 dp[i]
                    // dp[i] 表示数字 i  需要完全平方数的最少数量
                    // 这个时候 dp[i] 为获取数字为 square.get(j) 的那 1 个完全平方数
                    // 加上获取数字为 i-square.get(j) 最少需要 dp[i-square.get(j)] 个数
                    dp[i] = dp[i-square.get(j)] + 1;
                }
            }
        }

        // dp[n] 表示数字 n 需要完全平方数的最少数量
        // 返回这个结果就行
        return dp[n];

    }
}

# **2、**C++ 代码

class Solution {
public:
    int numSquares(int n) {
        // 设置一个数组,用来存储小于 n 的那些完全平方数
        vector<int> square;

        // 通过一个下标来计算
        int idx = 1;

        // 直到 idx * idx 超过了 n 为止
        while (idx * idx <= n) {
            // square 存储小于 n 的那些完全平方数
            square.push_back(idx * idx);

            // idx 累加
            idx++;
        }

        // dp[0] 表示数字 0  需要完全平方数的最少数量
        // dp[1] 表示数字 0  需要完全平方数的最少数量
        // dp[i] 表示数字 i  需要完全平方数的最少数量
        // 先让 dp 初始化为 -1,代表 dp[i] 还没有计算
        vector<int> dp(n + 1,-1);

        // dp[0] 表示数字 0  需要完全平方数的最少数量
        dp[0] = 0;
        
        // 开始填充 dp[]
        for(int i = 1 ; i <= n ;i++){
            
            // 在每次填充的过程中,都去遍历 square 数组
            for(int j = 0 ;j < square.size();j++){
                // 如果发现此时 square 的元素值大于了 i
                // 那么 square 后面的那些元素没有必要参与进来计算 i 了
                // 直接退出当前的 j 的循环判断,让 i++
                if(square[j] > i){
                    break;
                }

                // 否则,如果 dp[i] 还没有找到数字 i 需要完全平方数的最少数量
                // 或者此时计算的新值更小,那么更新 dp[i]
                if(dp[i] == -1 || dp[i] > dp[i-square[j]] + 1){

                    // 更新 dp[i]
                    // dp[i] 表示数字 i  需要完全平方数的最少数量
                    // 这个时候 dp[i] 为获取数字为 square.get(j) 的那 1 个完全平方数
                    // 加上获取数字为 i-square.get(j) 最少需要 dp[i-square.get(j)] 个数
                    dp[i] = dp[i-square[j]] + 1;
                }
            }
        }

        // dp[n] 表示数字 n 需要完全平方数的最少数量
        // 返回这个结果就行
        return dp[n];
    }
};

# 3、Python 代码

class Solution:
    def numSquares(self, n: int) -> int:
        # 设置一个数组,用来存储小于 n 的那些完全平方数
        square = []

        # 通过一个下标来计算
        idx = 1

        # 直到 idx * idx 超过了 n 为止
        while idx * idx <= n : 
            # square 存储小于 n 的那些完全平方数
            square.append(idx * idx)

            # idx 累加
            idx+= 1
    

        # dp[0] 表示数字 0  需要完全平方数的最少数量
        # dp[1] 表示数字 0  需要完全平方数的最少数量
        # dp[i] 表示数字 i  需要完全平方数的最少数量
        # 先让 dp 初始化为 -1,代表 dp[i] 还没有计算
        dp = [-1 for _ in range( n + 1 )]

        # dp[0] 表示数字 0  需要完全平方数的最少数量
        dp[0] = 0
        
        # 开始填充 dp[]
        for i in range( 1 , n + 1 ) : 
            
            # 在每次填充的过程中,都去遍历 square 数组
            for j in range( 0 ,len(square) ) :  
                # 如果发现此时 square 的元素值大于了 i
                # 那么 square 后面的那些元素没有必要参与进来计算 i 了
                # 直接退出当前的 j 的循环判断,让 i++
                if square[j] > i: 
                    break
                

                # 否则,如果 dp[i] 还没有找到数字 i 需要完全平方数的最少数量
                # 或者此时计算的新值更小,那么更新 dp[i]
                if dp[i] == -1 or dp[i] > dp[i-square[j]] + 1 : 

                    # 更新 dp[i]
                    # dp[i] 表示数字 i  需要完全平方数的最少数量
                    # 这个时候 dp[i] 为获取数字为 square.get(j) 的那 1 个完全平方数
                    # 加上获取数字为 i-square.get(j) 最少需要 dp[i-square.get(j)] 个数
                    dp[i] = dp[i-square[j]] + 1
      

        # dp[n] 表示数字 n 需要完全平方数的最少数量
        # 返回这个结果就行
        return dp[n]